//
// Created on 2024/7/1.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".

#ifndef OHOS_VIDEO_ENCODER_H
#define OHOS_VIDEO_ENCODER_H

#include <native_image/native_image.h>
#include <queue>
#include <memory>
#include <mutex>
#include <string>
#include <multimedia/player_framework/native_avcodec_videoencoder.h>
#include <multimedia/player_framework/native_avcapability.h>
#include <multimedia/player_framework/native_avcodec_base.h>
#include <multimedia/player_framework/native_avformat.h>
#include <multimedia/player_framework/native_avbuffer.h>
#include <thread>

#include "egl_render_context.h"
#include "ohos_gl_drawer.h"
#include "shader_program.h"

namespace webrtc {
namespace ohos {

struct FormatInfo {
  int32_t videoWidth {1216};
  int32_t videoHeight {2688};
  double frameRate {30.0};
  int64_t bitrate {3000000};
  OH_AVPixelFormat pixelFormat {AV_PIXEL_FORMAT_NV21};
  bool rangeFlag {false};
  int32_t primary = static_cast<int32_t>(OH_ColorPrimary::COLOR_PRIMARY_BT709);
  int32_t transfer = static_cast<int32_t>(OH_TransferCharacteristic::TRANSFER_CHARACTERISTIC_BT709);
  int32_t matrix = static_cast<int32_t>(OH_MatrixCoefficient::MATRIX_COEFFICIENT_IDENTITY);
  int32_t profile {OH_AVCProfile::AVC_PROFILE_BASELINE};
  int32_t rateMode {OH_VideoEncodeBitrateMode::CBR};
  int32_t frameInterval = 0;
};

class OhosVideoEncoder {
public:
    enum class EncodeStat {
        NONE = 0,
        CONFIGUED,
        STOP,
        RUNNING,
        RELEASE,
    };
    OhosVideoEncoder() = default;
    ~OhosVideoEncoder();
    FormatInfo formatInfo;
    int32_t Create();
    int32_t Config();
    int32_t Start();
    int32_t Stop();
    void Release();
    const EncodeStat &Stat();
    static void OnNewOutputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData);
    void StartThread();
    OHNativeWindow *nativeWindow_ {nullptr};

private:
    static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData);
    static void OnStreamChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData);
    static void OnNeedInputBuffer(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData);
    int32_t SetCallback();
    void DestroyNativeWindow();
    OH_AVCodec *encoder_ {nullptr};
    EncodeStat stat {EncodeStat::NONE};

    void DrawThread();
    mutable std::mutex wakeUpMutex_;
    std::atomic<bool> eosFlag_ {false};
    std::condition_variable wakeUpCond_;
    std::unique_ptr<std::thread> drawThread_;
    std::unique_ptr<OhosGLDrawer> OhosGLDrawer_;
    std::unique_ptr<EglRenderContext> eglRenderContext_;
    EGLSurface eglSurface_ = EGL_NO_SURFACE;
};

}
}

#endif
